#include "addface.h"
#include "ui_addface.h"
#include <QDebug>

using namespace cv;
using namespace dlib;
using namespace std;

extern CascadeClassifier cascade;

AddFace::AddFace(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::AddFace)
{
    ui->setupUi(this);

    this->pRegister = new Register;

    connect(ui->back,&QPushButton::clicked,[=](){
        emit this->back();
    });

    //连接compare信号和槽函数
    connect(this,SIGNAL(compare(cv::Mat)),this,SLOT(compare_face(cv::Mat)));

    //连接子窗口send信号和父窗口槽函数，传递人脸特征参数和身份信息
    connect(this->pRegister,SIGNAL(send(QString, QString, QString, QString, QString)),this,SLOT(add_face(QString, QString, QString, QString, QString)));

}

AddFace::~AddFace()
{
    delete ui;
}

void AddFace::on_begin_clicked()
{
    //调用摄像头
    VideoCapture video;
    video.open(0);

    //
    stop = false;
    int sig = 0;
    std::chrono::steady_clock::time_point startTime;

    //检测摄像头是否成功打开
    if (!video.isOpened()) {
    qDebug() << "摄像头加载出错！";
    exit(-1);
    }

    /*载入已训练的人脸识别算法，具体路径需要根据opencv库安装位置在config.h更改*/
    const string casPath = HAAR_PATH;

    //检测是否成功加载级联分类器
    if (!cascade.load(casPath)) {
        qDebug() << "算法加载失败！";
        exit(-1);
    }


    while (stop != true) {
        Mat vClip;
        video >> vClip;  //视频转为图像

        //若突然没有视频信号则结束
        if (vClip.empty()) {
            break;
        }

        //灰度化，减少计算
        Mat imgGray;
        cvtColor(vClip, imgGray, COLOR_BGR2GRAY);

        std::vector<Rect> faces(0);
        cascade.detectMultiScale(imgGray, faces, 1.1, 2, 0, Size(30, 30));  //调用人脸识别算法

        if (faces.size() > 0) {
            for (size_t i = 0; i < faces.size(); i++) {
                cv::rectangle(vClip, faces[i], Scalar(0, 0, 255), 2, 8, 0);  //生成矩形框出人脸
            }
        }

        //未检测到人脸
        if (faces.size() == 0) {
            ui->info->setText("未识别到人脸！");
            sig = 0;
        }

        //不止一张人脸（不能确定谁录入）
        else if (faces.size() > 1) {
            ui->info->setText("请逐个录入！");
            sig = 0;
        }

        //只有一张人脸
        else {
            ui->info->setText("请保持不动！");
            sig++;

            //检测到只有一张人脸3秒后进行比对，其间一旦出现不是一张人脸的情况，将重新计时
            if (sig == 1) {
                startTime = chrono::steady_clock::now();
            }

            if (sig >= 3) {
                chrono::steady_clock::time_point currentTime = chrono::steady_clock::now();
                chrono::duration<double> interval = currentTime - startTime;

                if (interval.count() >= 3.0 ) {
                    //dilb算法

                    dlib::shape_predictor predictor;
                    dlib::deserialize("D:/tideYH/dlib-19.24/shape_predictor_68_face_landmarks.dat") >> predictor;

                    std::vector<dlib::full_object_detection> face_landmarks;
                    for (size_t i = 0; i < faces.size(); i++) {
                        dlib::rectangle face_rect(faces[i].x, faces[i].y, faces[i].x + faces[i].width - 1, faces[i].y + faces[i].height - 1);
                        dlib::full_object_detection landmarks = predictor(dlib::cv_image<unsigned char>(imgGray), face_rect);
                        face_landmarks.push_back(landmarks);
                    }

                    Mat detect;
                    for (size_t i = 0; i < face_landmarks.size(); i++) {
                        Mat feature(1, 136, CV_32FC1, Scalar::all(0.0));
                        dlib::full_object_detection landmarks = face_landmarks[i];
                        int k = 0;
                        for (int j = 0; j < 68; j++) {
                            feature.at<float>(0, k++) = landmarks.part(j).x();
                            feature.at<float>(0, k++) = landmarks.part(j).y();
                        }
                        detect.push_back(feature);
                    }

                    emit compare(detect);  //发送compare信号进行比对
                    break;
                }

            }

        }

        //转换图片格式以输出
        Mat temp;
        cvtColor(vClip,temp,COLOR_BGR2RGB);
        QImage Qtemp = QImage((const unsigned char*)(temp.data),
                                temp.cols, temp.rows, temp.step,
                                QImage::Format_RGB888);

        ui->detect->setPixmap(QPixmap::fromImage(Qtemp));  //输出检测后带框的人脸

        waitKey(1); //waitkey 1ms的延迟
        QApplication::processEvents();
    }
}

//compare信号的槽函数，在这里本质上其实是函数调用
void AddFace::compare_face(Mat detect){
    /*输入信号：detect*/

    ui->info->setText("识别成功！");
    const int DIM = 136;  // 特征向量的固定维度
    // 连接数据库
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("myDatabase.db");
    if (!db.open()) {
        qDebug() << "Failed to establish database connection.";
        return;
    }

    {
        QSqlQuery query;
        query.prepare("SELECT name, id, face FROM face");
        if (!query.exec()) {
            qDebug() << "Error executing query: " << query.lastError();
            return;
        }

        double minDistance = std::numeric_limits<double>::max();
        QString closestName;
        QString closestId;

        while (query.next()) {
            QString name = query.value(0).toString();
            QString id = query.value(1).toString();
            QByteArray storedData = query.value(2).toByteArray();

            cv::Mat storedFace(1, DIM, CV_32F);
            memcpy(storedFace.ptr(), storedData.data(), DIM * sizeof(float));

            double distance = cv::norm(detect, storedFace, cv::NORM_L2);

            if (distance < minDistance) {
                minDistance = distance;
                closestName = name;
                closestId = id;
            }
        }

        if (minDistance < std::numeric_limits<double>::max()) {
            double threshold = 100.0;
            if (minDistance <= threshold) {
                qDebug() << "Face found in database. Closest match: Name:" << closestName << ", ID:" << closestId;
            }
            else {
                qDebug() << "Face not found in database.";
                this->pRegister->show();
                face = detect;
            }
        }
    }

    // 关闭数据库连接
    db.close();
}


//send信号槽函数，接收并处理身份信息和人脸数据
void AddFace::add_face(QString name, QString id, QString department, QString gender, QString age){
    //需要人脸的录入
    //包括输入的五个身份信息和人脸特征 new...
    // 创建数据库连接
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName("myDatabase.db");
    if (!db.open()) {
        qDebug() << "Failed to establish database connection.";
        return;
    }

    // 创建people表
    QSqlQuery query;
    if (!query.exec("CREATE TABLE IF NOT EXISTS people (name TEXT, id TEXT, department TEXT, gender TEXT, age INTEGER)")) {
        qDebug() << "Error creating table people: " << query.lastError();
        db.close();
        return;
    }

    // 创建face表
    if (!query.exec("CREATE TABLE IF NOT EXISTS face (name TEXT, id TEXT, face BLOB)")) {
        qDebug() << "Error creating table face: " << query.lastError();
        db.close();
        return;
    }

    // 插入数据到people表
    query.prepare("INSERT INTO people (name, id, department, gender, age) VALUES (?, ?, ?, ?, ?)");
    query.addBindValue(name);
    query.addBindValue(id);
    query.addBindValue(department);
    query.addBindValue(gender);
    query.addBindValue(age);
    if (!query.exec()) {
        qDebug() << "Error inserting data into people table: " << query.lastError();
        db.close();
        return;
    }

    // 插入数据到face表
    query.prepare("INSERT INTO face (name, id, face) VALUES (?, ?, ?)");
    query.addBindValue(name);
    query.addBindValue(id);
    QByteArray detectData((const char*)face.data, face.total() * face.elemSize());
    query.addBindValue(detectData);
    if (!query.exec()) {
        qDebug() << "Error inserting data into face table: " << query.lastError();
        db.close();
        return;
    }

    qDebug() << "Data inserted successfully.";

    // 关闭数据库连接
    db.close();
}




//停止按钮，停止检测，清屏
void AddFace::on_stop_clicked()
{
    stop = true;
    ui->info->clear();
    ui->detect->clear();
}

//返回按钮，停止检测，清屏并返回上一界面
void AddFace::on_back_clicked()
{
    stop = true;
    ui->info->clear();
    ui->detect->clear();
}

